// servicerequest
package servicerequest

import (
	"encoding/json"
	"errors"
	"os"
	"path"
	//	"fmt"
	"io"
	"log"
	"net/http"
	"strconv"
	"swim/contain"
	"swim/etc"
	"swim/lang"
	"swim/redisclient"
	"swim/request"
	//	"swim/serviceclient"
	"swim/swdb"
	"swim/util"
	"swim/util/nuid"
	"swim/util/sec"
	"time"
)

func OnService(w http.ResponseWriter, r *http.Request) {
	if r.Method == "GET" {
		query := r.URL.Query()
		get_act := query.Get("act")
		if get_act != "" {
			switch get_act {
			case "login":
				onLogin(w, r)
			case "logout":
				onLogOut(w, r)
			case "webmsg":
				onWebMsg(w, r)
			case "chpwdview":
				onChangePwdView(w, r)
			case "gettaskview":
				onGetTaskView(w, r)
			}
		}
	} else {
		//请求的是登陆数据，那么执行登陆的逻辑判断
		//sLang := r.FormValue("lang")
		act := r.FormValue("act")
		switch act {
		case "login":
			onLogin(w, r)
		case "logout":
			onLogOut(w, r)
		case "getstatus":
			onGetStatus(w, r)
		case "sendmsg":
			onSendMsg(w, r)
		case "getmsg":
			onGetMsg(w, r)
		case "remove":
			//onRemove(w, r)
		case "changepwd":
			onChangePwd(w, r)
		case "gettask":
			onGetTaskList(w, r)
		case "customer_m":
			onCustomerManger(w, r)
		case "customer_add":
			onAddCustomer(w, r)
		case "offlinemsg_m":
			onOfflineMsgManger(w, r)
		}

		//fmt.Println("username:", r.Form["username"])
		//fmt.Println("password:", r.Form["password"])
	}
}

type Sizer interface {
	Size() int64
}

func OnUploadFile(w http.ResponseWriter, r *http.Request) {
	if r.Method == "POST" {
		act := r.FormValue("act")
		sid := r.FormValue("sid")           //自身ID
		peer_sid := r.FormValue("peer_sid") //对方ID
		cType := r.FormValue("type")        //是否是服务端
		sLang := r.FormValue("lang")        //语言设置

		if !checkSID(sid) || !checkSID(peer_sid) {
			return
		}
		if act != "up" {
			return
		}
		if !lang.CheckLang(sLang) {
			return
		}
		iType, cErr := strconv.Atoi(cType)
		if cErr != nil {
			return
		}
		var sendMsg request.WebMsg
		var sWebId, sServiceId, fileID, fileLink string
		if iType == etc.S_CTYPE_WEB {
			sWebId = sid
			sServiceId = peer_sid
		} else if iType == etc.S_CTYPE_SCLIENT {
			sWebId = peer_sid
			sServiceId = sid
		}
		cWeb, bFind := contain.G_webClients.FindClient(sWebId)
		if !bFind {
			util.WriteMsgBack(w, "user_not_online", sLang)
			return
		} else {
			if cWeb.CheckSendTooMuch() {
				writeMsgBack(w, "", sLang)
				return
			}
		}
		sService, bServiceFind := contain.G_ServiceSessionPool.FindSessionBySid(sServiceId)
		if !bServiceFind {
			util.WriteMsgBack(w, "user_not_online", sLang)
			return
		} else {
			if sService.CheckSendTooMuch() {
				writeMsgBack(w, "", sLang)
				return
			}
		}
		if iType == etc.S_CTYPE_WEB {
			fileID = cWeb.TmpName
		} else if iType == etc.S_CTYPE_SCLIENT {
			fileID = sService.UserService.User.Account
		}
		file, head, err := r.FormFile("sendfile")
		if err != nil {
			log.Println(err)
			util.WriteMsgBack(w, "empty_file", sLang)
			return
		}
		defer file.Close()
		//判断文件大小
		filesize := file.(Sizer).Size()
		if filesize == 0 {
			return
		}
		if filesize > etc.SwImConfiger.MaxUploadSize {
			util.WriteMsgBack(w, "upload_file_too_large", sLang)
			return
		}
		//创建文件
		fullFileName := etc.SwImConfiger.UploadFilePath + fileID + "_" + head.Filename
		fW, err := os.Create(fullFileName)
		if err != nil {
			errMsg := "Crete file " + fullFileName + " error!"
			log.Println(errMsg)
			writeMsgBack(w, errMsg, sLang)
			return
		}
		defer fW.Close()
		_, err = io.Copy(fW, file)
		if err != nil {
			log.Println("Save the file error!")
			util.WriteMsgBack(w, "upload_file_too_large", sLang)
			//writeMsgBack(w, "Save the file error!", sLang)
			return
		}
		fExt := path.Ext(head.Filename)
		if fExt == ".jpg" || fExt == ".gif" || fExt == ".png" {
			fileLink = "<img src='" + etc.SwImConfiger.GetFileUrl + fileID + "_" + head.Filename +
				"' width='20%' height='20%' >"
		} else {
			fileLink = "<a href='" + etc.SwImConfiger.GetFileUrl + fileID + "_" + head.Filename +
				"' target='_blank'>" + head.Filename + "</a>"
		}
		sendMsg.Msg = fileLink
		if iType == etc.S_CTYPE_WEB {
			sendMsg.Name = lang.GetText("nick_i", sLang)
			cWeb.WriteMsg(sendMsg)
			sendMsg.Name = cWeb.TmpName
			sService.WriteMsg(sendMsg)

			swdb.WriteMsgLog(etc.S_SAY_C2S, util.GetIpFromIPort(r.RemoteAddr), sid, "",
				etc.SwImConfiger.GetFileUrl+fileID+"_"+head.Filename, sService.UserService.User.Account, peer_sid)
		} else if iType == etc.S_CTYPE_SCLIENT {
			sendMsg.Name = sService.UserService.User.Name
			cWeb.WriteMsg(sendMsg)
			sendMsg.Name = lang.GetText("nick_i", sLang)
			sService.WriteMsg(sendMsg)
			swdb.WriteMsgLog(etc.S_SAY_S2C, util.GetIpFromIPort(r.RemoteAddr), peer_sid, "",
				etc.SwImConfiger.GetFileUrl+fileID+"_"+head.Filename, sService.UserService.User.Account, sid)
		}
		util.WriteMsgBack(w, "upload_file_ok", sLang)
	}
}

func onLogin(w http.ResponseWriter, r *http.Request) {
	account := r.FormValue("name")
	pwd := r.FormValue("password")
	sLang := r.FormValue("lang")
	if !lang.CheckLang(sLang) {
		return
	}

	iCount, err := getLoginCount(account)
	if err != nil {
		setLoginCount(account, 1)
	}
	if !isOKAccount(account, pwd) {
		util.WriteMsgBack(w, "user_or_pwd_illegal", sLang)
	} else if iCount <= etc.MAX_USER_LOGIN && swdb.CheckServiceUser(account, pwd) {
		sUser, err := swdb.QueryServiceUser(account)
		if err == nil {
			swdb.UpdateServiceUserLogin(account)
			setLoginCount(account, 0)
			sClient := contain.G_servieceGroup.AddClient(sUser, w, r.RemoteAddr)
			locals := make(map[string]interface{})
			locals["name"] = sClient.User.Name
			locals["account"] = sClient.User.Account
			locals["login_id"] = sClient.LoginId
			util.RenderHtml(w, sLang+"service", locals)
			//	sUserJson, _ := json.Marshal(sUser)
			//	io.WriteString(w, string(sUserJson))
		} else {

		}

	} else {
		iCount++
		setLoginCount(account, iCount)
		if iCount > etc.MAX_USER_LOGIN {
			util.WriteMsgBack(w, "pwd_error_too_much", sLang)
		} else {
			util.WriteMsgBack(w, "user_or_pwd_error", sLang)
		}
	}
}

func isOKAccount(account, pwd string) bool {
	bRet := true
	if len(account) > etc.MAX_USER_NAME || account == "" ||
		len(pwd) > etc.MAX_PASSWORD || pwd == "" {
		bRet = false
	}

	return bRet
}

func onLogOut(w http.ResponseWriter, r *http.Request) {
	mode := r.FormValue("mode")
	login_id := r.FormValue("login_id")
	if login_id == "" || len(login_id) > etc.MAX_SID_LEN {
		return
	}
	//	log.Printf("%s--%s\n", mode, login_id)
	c, bFind := contain.G_servieceGroup.FindClientByLoginId(login_id)
	if bFind {
		contain.G_ServiceSessionPool.RemoveSessionByAccount(c.User.Account)
		contain.G_servieceGroup.RemoveClient(login_id)
	}
	m, ok := util.String(etc.S_LOG_OUT_NORMAL)
	if ok && mode == m {
		util.Redirect(w, "/")
	} else {

	}
}

func onGetStatus(w http.ResponseWriter, r *http.Request) {
	login_id := r.FormValue("login_id")
	if !checkSID(login_id) {
		return
	}
	account := r.FormValue("account")
	if len(account) > etc.MAX_USER_NAME || account == "" {
		return
	}
	c, bFind := contain.G_servieceGroup.FindClientByLoginId(login_id)
	if bFind {
		if c.User.Account == account {
			//查找改用户的待接入会话列表
			peer_sid, sid, iFindSession := c.GetSession()
			if iFindSession == 1 {
				ret := "{\"r\":\"1\",\"peer_sid\":\"" + peer_sid + "\",\"sid\":\"" + sid + "\"}"
				io.WriteString(w, ret)
				return
			} else if iFindSession == 2 {
				ret := "{\"r\":\"2\",\"peer_sid\":\"" + peer_sid + "\",\"url\":\"" + sid + "\"}"
				io.WriteString(w, ret)
				return
			}
		}
	}
	reStr := "{\"r\":\"0\"}"
	io.WriteString(w, reStr)
}

//根据传入的SID显示服务端对话界面
func onWebMsg(w http.ResponseWriter, r *http.Request) {
	query := r.URL.Query()
	sid := query.Get("sid")           //服务ID
	peer_sid := query.Get("peer_sid") //对方ID
	slang := query.Get("lang")        //得到语言标识
	if !lang.CheckLang(slang) {
		return
	}
	if !checkSID(sid) || !checkSID(peer_sid) {
		return
	}
	c, bFind := contain.G_webClients.FindClient(peer_sid)
	if bFind {
		locals := make(map[string]interface{})
		locals["nickname"] = c.TmpName
		locals["cardflag"] = "1"
		locals["peer_sid"] = peer_sid //web sid
		locals["sid"] = sid           //当前匿名WEB客户端的SID
		locals["card"] = c.TmpName
		locals["ctype"] = etc.S_CTYPE_SCLIENT
		locals["send_url"] = "/service/"
		locals["get_url"] = "/service/"
		locals["down_plug_url"] = "/static/plugin/setup_imgsvr.exe"
		util.RenderHtml(w, slang+"message", locals)
	}
}
func setLoginCount(account string, iCount int) error {

	key := account + "_login"
	rErr := redisclient.G_cache.Put(key, iCount, 1800*time.Second)

	return rErr
}

func getLoginCount(account string) (int, error) {
	var iCount int
	var err error
	key := account + "_login"
	v := redisclient.G_cache.Get(key)

	value, ok := util.String(v)
	if !ok {
		err = errors.New("It's not ok for type int")
	} else {
		i, cErr := strconv.Atoi(value)
		if cErr == nil {
			iCount = i
		} else {
			err = cErr
		}
	}
	return iCount, err
}

func setLoginCustomerPwd(account string) error {
	key := account + "_sec_key"
	value := nuid.Next()
	rErr := redisclient.G_cache.Put(key, value, 3600*time.Second)
	return rErr
}

func checkSID(sid string) bool {
	if sid == "" || len(sid) > etc.MAX_SID_LEN {
		return false
	}
	return true
}
func onGetMsg(w http.ResponseWriter, r *http.Request) {
	sid := r.FormValue("sid") //自身ID
	if !checkSID(sid) {
		return
	}
	sService, bFind := contain.G_ServiceSessionPool.FindSessionBySid(sid)
	if bFind {
		webMsg, err := sService.GetMsg()
		if err == nil {
			msg, sErr := json.Marshal(webMsg)
			if sErr == nil {
				//log.Println(string(msg))
				io.WriteString(w, string(msg))
			}
		}
	}
}

func onSendMsg(w http.ResponseWriter, r *http.Request) {
	sid := r.FormValue("sid")           //自身ID
	peer_sid := r.FormValue("peer_sid") //对方ID
	msg := r.FormValue("msg")
	if !checkSID(sid) || !checkSID(peer_sid) {
		return
	}
	if len(msg) > 2*etc.MAX_MSG_LEN {
		return
	}
	var webMsg request.WebMsg
	webMsg.Msg = msg
	sService, bFind := contain.G_ServiceSessionPool.FindSessionBySid(sid)
	if bFind {
		webMsg.Name = sService.UserService.User.Name
	}
	cWeb, bFindWeb := contain.G_webClients.FindClient(peer_sid)
	if bFindWeb {
		bWrite := cWeb.WriteMsg(webMsg)
		if !bWrite {
			reStr := "{\"r\":\"-2\"}"
			io.WriteString(w, reStr)
			return
		}
		if bFind && bWrite {
			swdb.WriteMsgLog(etc.S_SAY_S2C, util.GetIpFromIPort(r.RemoteAddr), peer_sid, webMsg.Msg,
				"", sService.UserService.User.Account, sid)
		}
		reStr := "{\"r\":\"1\"}"
		io.WriteString(w, reStr)
	}
}
func onRemove(w http.ResponseWriter, r *http.Request) {
	sid := r.FormValue("sid")           //自身ID
	peer_sid := r.FormValue("peer_sid") //对方ID
	if !checkSID(sid) || !checkSID(peer_sid) {
		return
	}
	s, bFind := contain.G_ServiceSessionPool.FindSessionBySid(sid)
	if bFind {
		s.UserService.RemoveSession(peer_sid)
	}
	contain.G_ServiceSessionPool.RemoveSession(sid)
	reStr := "{\"r\":\"1\"}"
	io.WriteString(w, reStr)
}

func onChangePwdView(w http.ResponseWriter, r *http.Request) {
	login_id := r.FormValue("login_id") //登录ID
	if !checkSID(login_id) {
		return
	}
	slang := r.FormValue("lang") //得到语言标识
	if !lang.CheckLang(slang) {
		return
	}
	c, bFind := contain.G_servieceGroup.FindClientByLoginId(login_id)
	if bFind {
		locals := make(map[string]interface{})
		locals["account"] = c.User.Account
		locals["login_id"] = login_id
		util.RenderHtml(w, slang+"changepwd", locals)
	} else {
		writeMsgBack(w, "", slang)
	}
}

func onChangePwd(w http.ResponseWriter, r *http.Request) {
	login_id := r.FormValue("login_id") //登录ID
	oldpwd := r.FormValue("oldpwd")
	newpwd := r.FormValue("newpwd")
	if !checkSID(login_id) {
		return
	}
	slang := r.FormValue("lang") //得到语言标识
	if !lang.CheckLang(slang) {
		return
	}
	//密码不能为空的
	if len(newpwd) == 0 {
		return
	}
	c, bFind := contain.G_servieceGroup.FindClientByLoginId(login_id)
	if bFind {
		account := c.User.Account
		var reStr string
		if !swdb.CheckServiceUser(account, oldpwd) {
			reStr = "{\"r\":\"1\"}"
			io.WriteString(w, reStr)
			return
		}
		bConfirm := swdb.ChangeUserPwd(account, newpwd)

		if bConfirm {
			reStr = "{\"r\":\"0\"}"
		} else {
			reStr = "{\"r\":\"2\"}"
		}

		io.WriteString(w, reStr)
	}
}

func onGetTaskView(w http.ResponseWriter, r *http.Request) {
	login_id := r.FormValue("login_id") //登录ID
	if !checkSID(login_id) {
		return
	}
	locals := make(map[string]interface{})
	locals["login_id"] = login_id
	util.RenderHtml(w, "onlinetask", locals)
}

func onGetTaskList(w http.ResponseWriter, r *http.Request) {
	login_id := r.FormValue("login_id") //登录ID
	if !checkSID(login_id) {
		return
	}
	online_tasks := []request.TaskOnline{}
	c, bFind := contain.G_servieceGroup.FindClientByLoginId(login_id)
	if bFind {
		for peer_sid, sid := range c.Sessions {
			task := request.TaskOnline{}
			task.Sid = sid
			task.Peer_sid = peer_sid
			sc, bFindService := contain.G_ServiceSessionPool.FindSessionBySid(sid)
			if bFindService {
				task.Msgcount, _ = sc.GetMsgLen()
			}
			online_tasks = append(online_tasks, task)
		}
		tasksBytes, err := json.Marshal(online_tasks)
		if err == nil {
			//log.Println(string(tasksBytes))
			io.WriteString(w, string(tasksBytes))
		}
	}

}
func setAccountTmpCheck(account string) (string, error) {

	key := account + "_sec_key"
	value := nuid.Next()
	rErr := redisclient.G_cache.Put(key, value, 1800*time.Second)
	return value, rErr
}

func getAccountTmpCheck(account string) (string, bool) {
	key := account + "_sec_key"
	v := redisclient.G_cache.Get(key)
	value, ok := util.String(v)
	return value, ok
}

func onCustomerManger(w http.ResponseWriter, r *http.Request) {
	login_id := r.FormValue("login_id") //登录ID
	if !checkSID(login_id) {
		return
	}
	reStr := "{\"r\":\"1\"}"
	c, bFind := contain.G_servieceGroup.FindClientByLoginId(login_id)
	if bFind {
		tmpPwd, err := setAccountTmpCheck(c.User.Account)
		if err == nil {
			secPwd := sec.PasswdMd5(tmpPwd)
			url := etc.SwImConfiger.CustomerUrl + "?user=" + c.User.Account + "&pwd=" + secPwd
			reStr = "{\"r\":\"0\",\"url\":\"" + url + "\"}"
		}
	}
	io.WriteString(w, reStr)
}
func onOfflineMsgManger(w http.ResponseWriter, r *http.Request) {
	login_id := r.FormValue("login_id") //登录ID
	if !checkSID(login_id) {
		return
	}
	reStr := "{\"r\":\"1\"}"
	c, bFind := contain.G_servieceGroup.FindClientByLoginId(login_id)
	if bFind {
		tmpPwd, err := setAccountTmpCheck(c.User.Account)
		if err == nil {
			secPwd := sec.PasswdMd5(tmpPwd)
			url := etc.SwImConfiger.OfflineMsgMangerUrl + "?user=" + c.User.Account + "&pwd=" + secPwd
			reStr = "{\"r\":\"0\",\"url\":\"" + url + "\"}"
		}
	}
	io.WriteString(w, reStr)
}

func onAddCustomer(w http.ResponseWriter, r *http.Request) {
	sid := r.FormValue("sid")
	peer_id := r.FormValue("peer_id") //web客户ID
	if !checkSID(peer_id) || !checkSID(sid) {
		return
	}

	reStr := "{\"r\":\"1\"}"
	s, bFind := contain.G_ServiceSessionPool.FindSessionBySid(sid)
	if bFind {
		account := s.UserService.User.Account
		bGet := false
		var getPwd string
		getPwd, bGet = getAccountTmpCheck(account)
		if !bGet {
			tmpPwd, err := setAccountTmpCheck(account)
			if err == nil {
				secPwd := sec.PasswdMd5(tmpPwd)
				url := etc.SwImConfiger.AddCustomerUrl + "?user=" + account + "&pwd=" + secPwd +
					"&mapsid=" + peer_id
				s.UserService.AddCustomerUrl(url)
				reStr = "{\"r\":\"0\",\"url\":\"" + url + "\"}"
			}
		} else {
			secPwd := sec.PasswdMd5(getPwd)
			url := etc.SwImConfiger.AddCustomerUrl + "?user=" + account + "&pwd=" + secPwd +
				"&mapsid=" + peer_id
			s.UserService.AddCustomerUrl(url)
			reStr = "{\"r\":\"0\",\"url\":\"" + url + "\"}"
		}
	}
	io.WriteString(w, reStr)
}

func writeMsgBack(w io.Writer, strMsg, sLang string) {
	hintMap := make(map[string]interface{})
	hintMap["msg"] = strMsg
	util.RenderHtml(w, sLang+"hintback", hintMap)
}
